#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <mutex>
#include <tuple>
#include "base/Bytes.h"
#include <sw/redis++/redis++.h>

namespace zeroplus::mq
{
    using Attrs = std::vector<std::pair<std::string, std::string>>;
    using Item = std::pair<std::string, sw::redis::Optional<Attrs>>;
    using ItemStream = std::vector<Item>;
    /*
    消息 ID：std::string 类型，表示消息的唯一标识。
    消费者名称：std::string 类型，表示处理该消息的消费者名称。
    消息时间戳：long long 类型，表示消息被分配给消费者的时间戳（毫秒级）。
    消息重试次数：long long 类型，表示该消息被重新分配给其他消费者的次数。
    */
    using PendingItem = std::tuple<std::string, std::string, long long, long long>;
    /*
    消息 ID：std::string 类型，表示消息的唯一标识。
    消息内容：kv
    */
    using ClaimedItem = std::tuple<std::string, std::unordered_map<std::string, std::string>>;
    class MessageQueue
    {
    private:
        std::shared_ptr<sw::redis::Redis> redis_;
        std::string messageOffset_;
        std::unordered_map<std::string, bool> consumerGroupMap_;

    public:
        MessageQueue(std::shared_ptr<sw::redis::Redis> redisFd);
        virtual ~MessageQueue();
        // 创建topic队列
        std::string CreateStreams(const std::string &topic);
        // 从redis stream中写入数据
        std::string WriteToStorage(const std::string &topic, const Bytes &message);
        // 从redis stream中读取数据
        std::tuple<Bytes, std::string, bool> ReadFromStorage(const std::string &topic, const std::string &messageId, const int &count = 1);
        std::tuple<Bytes, std::string, bool> ReadFromStorage(const std::string &topic, const std::string &consumerGroup, const std::string &consumerId,
                                                             const int &count = 1, const int &blockSeconds = 0);
        // 获取队列的大小
        long long Length(const std::string &topic);
        // 检查key是否存在
        long long IsTopicExists(const std::vector<std::string> &topicList);
        // 扫描所有key，并返回所有stream类型的key
        std::vector<std::string> GetAllTopic();
        // 消息应答
        bool Acknowledge(const std::string &topic, const std::string &messageId, const std::string &groupName);
        // 查找PEL中的消息
        std::vector<PendingItem> SerachPendingMessage(const std::string &topic, const std::string &consumerGroup, const std::string &consumerId, const std::string &messageId);
        // 重新分配PEL中的消息
        std::vector<ClaimedItem> ClaimPendingMessage(const std::string &topic, const std::string &consumerGroup, const std::string &consumerId, const std::string &messageId);
    };
}
